home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / DEMON / RISCOS2 / TCP_131S.ARC / c / ARP < prev    next >
Text File  |  1992-03-17  |  13KB  |  364 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  3.  */                
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <time.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "timer.h"
  10. #include "ip.h"
  11. #include "misc.h"
  12. #include "icmp.h"
  13. #include "iface.h"
  14. #include "ax25.h"
  15. #include "arp.h"
  16.  
  17. static void arp_output(struct interface *, int16, int32);
  18. static unsigned arp_hash(int16, int32);
  19.  
  20. extern int32 ip_addr;           /* Our IP address */
  21.  
  22. /* ARP entries for particular subnetwork types. The table values
  23.  * are filled in by calls to arp_init() at device attach time
  24.  */
  25. #define NTYPES  9
  26. struct arp_type arp_type[NTYPES];
  27.  
  28. /* Hash table headers */
  29. struct arp_tab *arp_tab[ARPSIZE];
  30.  
  31. struct arp_stat arp_stat;
  32.  
  33. /* Initialize an entry in the ARP table
  34.  * Called by the device driver at attach time
  35.  */
  36. int arp_init(unsigned int hwtype, int hwalen, int iptype, int arptype,
  37.              char *bdcst, int (*format)(), int (*scan)())
  38. {
  39.         register struct arp_type *at;
  40.  
  41.         if(hwtype >= NTYPES)
  42.                 return -1;      /* Table too small */
  43.  
  44.         at = &arp_type[hwtype];
  45.         at->hwalen = (int16)hwalen;
  46.         at->iptype = (int16)iptype;
  47.         at->arptype = (int16)arptype;
  48.         at->bdcst = bdcst;
  49.         at->format = format;
  50.         at->scan = scan;
  51.         return 0;
  52. }
  53.  
  54. /* Resolve an IP address to a hardware address; if not found,
  55.  * initiate query and return NULLCHAR.  If an address is returned, the
  56.  * interface driver may send the packet; if NULLCHAR is returned,
  57.  * res_arp() will have saved the packet on its pending queue,
  58.  * so no further action (like freeing the packet) is necessary.
  59.  */
  60. char *res_arp(struct interface *interface, int16 hardware, int32 target, struct mbuf *bp)
  61. {
  62.         register struct arp_tab *arp;
  63.         struct ip ip;
  64.  
  65.         if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  66.                 return arp->hw_addr;
  67.         if(arp != NULLARP){
  68.                 /* Earlier packets are already pending, kick this one back
  69.                  * as a source quench
  70.                  */
  71.                 ntohip(&ip,&bp);
  72.                 icmp_output(&ip,bp,QUENCH,0,NULLICMP);
  73.                 free_p(bp);
  74.         } else {
  75.                /* Create an entry and put the datagram on the
  76.                 * queue pending an answer
  77.                 */
  78.                arp = arp_add(target,hardware,NULLCHAR,0,0);
  79.                enqueue(&arp->pending,bp);
  80.                arp_output(interface,hardware,target);
  81.         }
  82.         return NULLCHAR;
  83. }
  84. /* Handle incoming ARP packets. This is almost a direct implementation of
  85.  * the algorithm on page 5 of RFC 826, except for:
  86.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  87.  *    pending a reply to our ARP request.
  88.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  89.  * 3. Requests for IP addresses listed in our table as "published" are
  90.  *    responded to, even if the address is not our own.
  91.  */
  92. void arp_input(struct interface *interface, struct mbuf *bp)
  93. {
  94.         struct arp arp;
  95.         struct arp_tab *ap;
  96.         struct arp_type *at;
  97.         
  98.         arp_stat.recv++;
  99.         if(ntoharp(&arp,&bp) == -1)     /* Convert into host format */
  100.                 return;
  101.         if(arp.hardware >= NTYPES){
  102.                 /* Unknown hardware type, ignore */
  103.                 arp_stat.badtype++;
  104.                 return;
  105.         }
  106.         at = &arp_type[arp.hardware];
  107.         if(arp.protocol != at->iptype){
  108.                 /* Unsupported protocol type, ignore */
  109.                 arp_stat.badtype++;
  110.                 return;
  111.         }
  112.         if(uchar(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  113.                 /* Incorrect protocol addr length (different hw addr lengths
  114.                  * are OK since AX.25 addresses can be of variable length)
  115.                  */
  116.                 arp_stat.badlen++;
  117.                 return;
  118.         }
  119.         if(memcmp(arp.shwaddr,at->bdcst,at->hwalen) == 0){
  120.                 /* This guy is trying to say he's got the broadcast address! */
  121.                 arp_stat.badaddr++;
  122.                 return;
  123.         }
  124.         /* If this guy is already in the table, update its entry
  125.          * unless it's a manual entry (noted by the lack of a timer)
  126.          */
  127.         ap = NULLARP;   /* ap plays the role of merge_flag in the spec */
  128.         if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  129.          && ap->timer.start != 0){
  130.                 ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  131.         }
  132.         /* See if we're the address they're looking for */
  133.         if(arp.tprotaddr == ip_addr){
  134.                 if(ap == NULLARP)       /* Only if not already in the table */
  135.                         arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  136.  
  137.                 if(arp.opcode == ARP_REQUEST){
  138.                         /* Swap sender's and target's (us) hardware and protocol
  139.                          * fields, and send the packet back as a reply
  140.                          */
  141.                         memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  142.                         /* Mark the end of the sender's AX.25 address
  143.                          * in case he didn't
  144.                          */
  145.                         if(arp.hardware == ARP_AX25)
  146.                                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  147.  
  148.                         memcpy(arp.shwaddr,interface->hwaddr,at->hwalen);
  149.                         arp.tprotaddr = arp.sprotaddr;
  150.                         arp.sprotaddr = ip_addr;
  151.                         arp.opcode = ARP_REPLY;
  152.                         if((bp = htonarp(&arp)) == NULLBUF)
  153.                                 return;
  154.  
  155.                         if(interface->forw != NULLIF)
  156.                                 (*interface->forw->output)(interface->forw,
  157.                                  arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  158.                         else 
  159.                                 (*interface->output)(interface,arp.thwaddr,
  160.                                  interface->hwaddr,at->arptype,bp);
  161.                         arp_stat.inreq++;
  162.                 } else {
  163.                         arp_stat.replies++;
  164.                 }
  165.         } else if(arp.opcode == ARP_REQUEST
  166.                 && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  167.                 && ap->pub){
  168.                 /* Otherwise, respond if the guy he's looking for is
  169.                  * published in our table.
  170.                  */
  171.                 memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  172.                 /* Mark the end of the sender's AX.25 address
  173.                  * in case he didn't
  174.                  */
  175.                 if(arp.hardware == ARP_AX25)
  176.                         arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  177.                 memcpy(arp.shwaddr,ap->hw_addr,at->hwalen);
  178.                 arp.tprotaddr = arp.sprotaddr;
  179.                 arp.sprotaddr = ap->ip_addr;
  180.                 arp.opcode = ARP_REPLY;
  181.                 if((bp = htonarp(&arp)) == NULLBUF)
  182.                         return;
  183.                 if(interface->forw != NULLIF)
  184.                         (*interface->forw->output)(interface->forw,
  185.                          arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  186.                 else 
  187.                         (*interface->output)(interface,arp.thwaddr,
  188.                          interface->hwaddr,at->arptype,bp);
  189.                 arp_stat.inreq++;
  190.         }
  191. }
  192. /* Add an IP-addr / hardware-addr pair to the ARP table */
  193. struct arp_tab *
  194. arp_add(int32 ipaddr, int16 hardware, char *hw_addr, int16 hw_alen, int pub)
  195. {
  196.         struct mbuf *bp;
  197.         register struct arp_tab *ap;
  198.         unsigned hashval;
  199.  
  200.         if((ap = arp_lookup(hardware,ipaddr)) == NULLARP){
  201.                 /* New entry */
  202.                 if((ap = (struct arp_tab *)calloc(1,sizeof(struct arp_tab))) == NULLARP)
  203.                         return NULLARP;
  204.                 ap->timer.func = arp_drop;
  205.                 ap->timer.arg = (char *)ap;
  206.                 ap->hardware = hardware;
  207.                 ap->ip_addr = ipaddr;
  208.  
  209.                 /* Put on head of hash chain */
  210.                 hashval = arp_hash(hardware,ipaddr);
  211.                 ap->prev = NULLARP;
  212.                 ap->next = arp_tab[hashval];
  213.                 arp_tab[hashval] = ap;
  214.                 if(ap->next != NULLARP){
  215.                         ap->next->prev = ap;
  216.                 }
  217.         }
  218.         if(hw_addr == NULLCHAR){
  219.                 /* Await response */
  220.                 ap->state = ARP_PENDING;
  221.                 ap->timer.start = PENDTIME * (1000 / MSPTICK);
  222.         } else {
  223.                 /* Response has come in, update entry and run through queue */
  224.                 ap->state = ARP_VALID;
  225.                 ap->timer.start = ARPLIFE * (1000 / MSPTICK);
  226.                 if(ap->hw_addr != NULLCHAR)
  227.                         free(ap->hw_addr);
  228.                 if((ap->hw_addr = malloc(hw_alen)) == NULLCHAR){
  229.                         free((char *)ap);
  230.                         return NULLARP;
  231.                 }
  232.                 memcpy(ap->hw_addr,hw_addr,hw_alen);
  233.                 /* This kludge marks the end of an AX.25 address to allow
  234.                  * for optional digipeaters (insert Joan Rivers salute here)
  235.                  */
  236.                 if(hardware == ARP_AX25)
  237.                         ap->hw_addr[hw_alen-1] |= E;
  238.                 ap->pub = pub;
  239.                 while((bp = dequeue(&ap->pending)) != NULLBUF)
  240.                         ip_route(bp,0);
  241.         }
  242.         start_timer(&ap->timer);
  243.         return ap;
  244. }
  245.  
  246. /* Remove an entry from the ARP table */
  247. void arp_drop(register struct arp_tab *ap)
  248. {
  249.         if(ap == NULLARP)
  250.                 return;
  251.         stop_timer(&ap->timer); /* Shouldn't be necessary */
  252.         if(ap->next != NULLARP)
  253.                 ap->next->prev = ap->prev;
  254.         if(ap->prev != NULLARP)
  255.                 ap->prev->next = ap->next;
  256.         else
  257.                 arp_tab[arp_hash(ap->hardware,ap->ip_addr)] = ap->next;
  258.         if(ap->hw_addr != NULLCHAR)
  259.                 free(ap->hw_addr);
  260.         free_q(&ap->pending);
  261.         free((char *)ap);
  262. }
  263.  
  264. /* Look up the given IP address in the ARP table */
  265. struct arp_tab *arp_lookup(int16 hardware, int32 ipaddr)
  266. {
  267.         register struct arp_tab *ap;
  268.  
  269.         for(ap = arp_tab[arp_hash(hardware,ipaddr)]; ap != NULLARP; ap = ap->next){
  270.                 if(ap->ip_addr == ipaddr && ap->hardware == hardware)
  271.                         break;
  272.         }
  273.         return ap;
  274. }
  275. /* Send an ARP request to resolve IP address target_ip */
  276. static void arp_output(struct interface *interface, int16 hardware, int32 target)
  277. {
  278.         struct arp arp;
  279.         struct mbuf *bp;
  280.         struct arp_type *at;
  281.  
  282.         at = &arp_type[hardware];
  283.         if(interface->output == NULLFP)
  284.                 return;
  285.         
  286.         arp.hardware = hardware;
  287.         arp.protocol = at->iptype;
  288.         arp.hwalen = at->hwalen;
  289.         arp.pralen = sizeof(int32);
  290.         arp.opcode = ARP_REQUEST;
  291.         memcpy(arp.shwaddr,interface->hwaddr,at->hwalen);
  292.         arp.sprotaddr = ip_addr;
  293.         memset(arp.thwaddr,0,at->hwalen);
  294.         arp.tprotaddr = target;
  295.         if((bp = htonarp(&arp)) == NULLBUF)
  296.                 return;
  297.         (*interface->output)(interface,at->bdcst,
  298.                 interface->hwaddr,at->arptype,bp);
  299.         arp_stat.outreq++;
  300. }
  301.  
  302. /* Hash a {hardware type, IP address} pair */
  303. static unsigned arp_hash(int16 hardware, int32 ipaddr)
  304. {
  305.         register unsigned hashval;
  306.  
  307.         hashval = hardware;
  308.         hashval ^= hiword(ipaddr);
  309.         hashval ^= loword(ipaddr);
  310.         hashval %= ARPSIZE;
  311.         return hashval;
  312. }               
  313. /* Copy a host format arp structure into mbuf for transmission */
  314. struct mbuf *htonarp(register struct arp *arp)
  315. {
  316.         struct mbuf *bp;
  317.         register char *buf;
  318.  
  319.         if(arp == (struct arp *)NULL)
  320.                 return NULLBUF;
  321.         if((bp = alloc_mbuf(sizeof(struct arp))) == NULLBUF)
  322.                 return NULLBUF;
  323.  
  324.         buf = bp->data;
  325.  
  326.         buf = put16(buf,arp->hardware);
  327.         buf = put16(buf,arp->protocol);
  328.         *buf++ = arp->hwalen;
  329.         *buf++ = arp->pralen;
  330.         buf = put16(buf,arp->opcode);
  331.         memcpy(buf,arp->shwaddr,(int16)uchar(arp->hwalen));
  332.         buf += arp->hwalen;
  333.         buf = put32(buf,arp->sprotaddr);
  334.         memcpy(buf,arp->thwaddr,(int16)uchar(arp->hwalen));
  335.         buf += arp->hwalen;
  336.         buf = put32(buf,arp->tprotaddr);
  337.  
  338.         bp->cnt = buf - bp->data;
  339.         return bp;
  340. }
  341. /* Convert an incoming ARP packet into a host-format structure */
  342. int ntoharp(register struct arp *arp, struct mbuf **bpp)
  343. {
  344.         if(arp == (struct arp *)NULL || bpp == NULLBUFP)
  345.                 return -1;
  346.  
  347.         arp->hardware = pull16(bpp);
  348.         arp->protocol = pull16(bpp);
  349.         arp->hwalen = pullchar(bpp);
  350.         arp->pralen = pullchar(bpp);
  351.         arp->opcode = pull16(bpp);
  352.         pullup(bpp,arp->shwaddr,(int16)uchar(arp->hwalen));
  353.         arp->sprotaddr = pull32(bpp);
  354.         pullup(bpp,arp->thwaddr,(int16)uchar(arp->hwalen));
  355.  
  356.         arp->tprotaddr = pull32(bpp);
  357.  
  358.         /* Get rid of anything left over */
  359.         free_p(*bpp);
  360.         *bpp = NULLBUF;
  361.         return 0;
  362. }
  363.  
  364.